using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Jonathan.Controls;

namespace Jonathan.Classes
{
   /// <summary>
   /// Class with static methods and fields.
   /// </summary>
   public class Common
   {
      /// <summary>
      /// Bible Table in a bible Database.
      /// </summary>
      public const string TABLE_BIBLES = "Bibles";

      /// <summary>
      /// Info table in a Jonathan Database.
      /// </summary>
      public const string TABLE_INFO = "Info";

      /// <summary>
      /// List table in a Jonathan Database.
      /// </summary>
      public const string TABLE_LIST = "List";

      /// <summary>
      /// Notes table in a Jonathan Database.
      /// </summary>
      public const string TABLE_NOTES = "Notes";

      /// <summary>
      /// Book List table in a Jonathan Database.
      /// </summary>
      public const string TABLE_BOOK_LIST = "BookList";

      /// <summary>
      /// Name of Jonathan's Help File.
      /// </summary>
      public const string HELP_FILE = "jonathan-help.chm";

      /// <summary>
      /// Application data XML file.
      /// </summary>
      public const string FILE_PROGRAM_DATA = "jData.xml";

      /// <summary>
      /// Database used to store verse notes.
      /// </summary>
      public const string DATABASE_VERSE_NOTES = "verseNotes.db";

      /// <summary>
      /// Preface string.
      /// </summary>
      public const string PREFACE = "Preface";

      /// <summary>
      /// Path to Folder where all data is stored.
      /// </summary>
      public static string DataFolder = Application.StartupPath + "\\" + "data\\";

      /// <summary>
      /// Database Type Bible.
      /// </summary>
      public const string TYPE_BIBLE = "Bible";

      /// <summary>
      /// Database Type Other Text.
      /// </summary>
      public const string TYPE_OTHER = "Other";

      /// <summary>
      /// Search Type Passage.
      /// </summary>
      public const string TYPE_PASSAGE = "Passage";

      /// <summary>
      /// Database Type Reference
      /// </summary>
      public const string TYPE_REFERENCE = "Reference";

      /// <summary>
      /// Database Type Daily (daily devotionaly).
      /// </summary>
      public const string TYPE_DAILY = "Daily";

      /// <summary>
      /// Name of Book Name Column in the Book List Table.
      /// </summary>
      public const string BOOK_NAME = "BookName";

      /// <summary>
      /// Abbreviation column name.
      /// </summary>
      public const string ABBREVIATION = "Abbreviation";

      /// <summary>
      /// Current Version of Jonathan.
      /// </summary>
      public const string JONATHAN_VERSION = "1.3";

      /// <summary>
      /// Enumeration to define how we are going to perform the search...
      /// </summary>
      public enum SearchCriteria
      {
         /// <summary>
         /// Search for all words in search text, but not in order.
         /// </summary>
         AllWords,
         /// <summary>
         /// Search for any of the words in the search text.
         /// </summary>
         AnyWord,
         /// <summary>
         /// Search for the exact phrase of the search text.
         /// </summary>
         Phrase
      }

      /// <summary>
      /// Creates a path for a round rectangle...
      /// </summary>
      /// <param name="r">Original Rectangle.</param>
      /// <param name="r1">Corner 1 radius.</param>
      /// <param name="r2">Corner 2 radius.</param>
      /// <param name="r3">Corner 3 radius.</param>
      /// <param name="r4">Corner 4 radius.</param>
      /// <returns>GraphicsPath of Round Rectangle.</returns>
      public static GraphicsPath RoundRect (RectangleF r, float r1, float r2, float r3, float r4)
      {
         float x = r.X, y = r.Y, w = r.Width, h = r.Height;
         GraphicsPath rr = new GraphicsPath ();
         rr.AddBezier (x, y + r1, x, y, x + r1, y, x + r1, y);
         rr.AddLine (x + r1, y, x + w - r2, y);
         rr.AddBezier (x + w - r2, y, x + w, y, x + w, y + r2, x + w, y + r2);
         rr.AddLine (x + w, y + r2, x + w, y + h - r3);
         rr.AddBezier (x + w, y + h - r3, x + w, y + h, x + w - r3, y + h, x + w - r3, y + h);
         rr.AddLine (x + w - r3, y + h, x + r4, y + h);
         rr.AddBezier (x + r4, y + h, x, y + h, x, y + h - r4, x, y + h - r4);
         rr.AddLine (x, y + h - r4, x, y + r1);
         return rr;
      }

      /// <summary>
      /// Returns if a string is numeric or not...
      /// </summary>
      /// <param name="val">String to test.</param>
      /// <returns>True if numeric, else false.</returns>
      public static bool IsNumeric (string val)
      {
         Double result;
         return Double.TryParse (val, System.Globalization.NumberStyles.Integer,
             System.Globalization.CultureInfo.CurrentCulture, out result);
      }

      /// <summary>
      /// Removes the HTML from the string...
      /// </summary>
      /// <param name="oldString">String with HTML.</param>
      /// <returns>String without HTML.</returns>
      public static string RemoveHtml (string oldString)
      {
         string newString = "";
         bool read = true;
         foreach (char t in oldString)
         {
            if (t == '<')
            {
               read = false;
            }
            else if (t == '>')
            {
               read = true;
            }
            else if (read)
            {
               newString += t;
            }
         }
         return newString;
      }

      /// <summary>
      /// Gets a connection string to a sqlite database.
      /// </summary>
      /// <param name="dbPath">Path to sqlite database.</param>
      /// <returns>Requested connection string.</returns>
      public static string ConnString (string dbPath)
      {
         return string.Format ("Data Source={0};Version=3;", dbPath);
      }

      /// <summary>
      /// Gets the text to place inside of a tooltip...
      /// </summary>
      /// <param name="passages">Passage List</param>
      /// <param name="source">Passage Source</param>
      /// <param name="command">Database command.</param>
      /// <returns>String Builder</returns>
      public static StringBuilder GetToolTipText (List<CPassage> passages, string source, SQLiteCommand command)
      {
         StringBuilder sb = new StringBuilder ();
         sb.Append ("<table>");

         if (command != null)
         {
            foreach (CPassage passage in passages)
            {
               command.CommandText = string.Format ("SELECT * FROM book_text WHERE Book='{0}' AND Chapter={1}{2}",
                  passage.Book, passage.Chapter, (!string.IsNullOrEmpty (passage.Verse)) ? " AND Verse=" + passage.Verse : string.Empty);
               SQLiteDataReader dataReader = command.ExecuteReader ();

               string book = Parser.GetBook (passage.Book, false);
               if (string.IsNullOrEmpty (book))
               {
                  if (string.IsNullOrEmpty (book))
                  {
                     string[] spBook = passage.Book.Split (' ');
                     book = spBook.Where (b => Char.IsLetter (b[0])).Aggregate (book, (current, b) => current + b[0].ToString ().ToUpper ());
                  }
               }

               //for (int a = 0; a < q.RowsReturned; a++)
               while (dataReader.Read ())
               {
                  int chapter = dataReader.GetInt32 (dataReader.GetOrdinal ("Chapter"));
                  int verse = dataReader.GetInt32 (dataReader.GetOrdinal ("Verse"));
                  string text = dataReader.GetString (dataReader.GetOrdinal ("Text"));

                  string pass = book + " " + chapter + ":" + verse;
                  sb.Append ("<tr passage=\"" + book + "|" + chapter + "|" + verse + "\">");
                  sb.Append ("<td align=\"left\" valign=\"top\"><a class=\"goto\" href=\"" + source +
                             "\" title=\"Goto " + passage.Book + " " + chapter + ":" + verse + "\">");
                  sb.Append (pass);
                  sb.Append ("</a></td>");
                  sb.Append ("<td align=\"left\" valign=\"top\">");
                  sb.Append (text);
                  sb.Append ("</td>");
                  sb.Append ("</tr>");

                  string footer = dataReader.GetString (dataReader.GetOrdinal ("Footer"));
                  if (!string.IsNullOrEmpty (footer))
                  {
                     sb.Append ("<tr><td align=\"left\" valign=\"top\">&nbsp;</td>");
                     sb.Append ("<td align=\"center\" valign=\"top\">");
                     sb.Append (footer);
                     sb.Append ("</td></tr>");
                  }
               }
               dataReader.Close ();
            }
         }
         sb.Append ("<tr><td align=\"right\" colspan=\"2\">Source | " + source + "</td></tr>");
         sb.Append ("</table>");
         return sb;
      }

      /// <summary>
      ///  Highlight All occurances of the given text.
      /// </summary>
      /// <param name="orgHtml">The HTML code.</param>
      /// <param name="text">Text to highlight.</param>
      /// <param name="caseSensitive">Is the highlighted text case sensitive</param>
      public static string HighlightHtml (string orgHtml, string text, bool caseSensitive)
      {
         if (!orgHtml.StartsWith ("<"))
            orgHtml = "<html>" + orgHtml;

         StringBuilder html = new StringBuilder ();
         string tempHtml = (caseSensitive) ? orgHtml : orgHtml.ToLower ();
         if (!caseSensitive)
            text = text.ToLower ();

         int start = 0;
         int lastFind = 0;
         while ((start = tempHtml.IndexOf (text, start)) != -1)
         {
            // Check to see if we are inside any tags...
            for (int a = start; a >= 0; a--)
            {
               if (orgHtml[a] == '>')
               {
                  html.Append (orgHtml.Substring (lastFind, start - lastFind));
                  html.Append ("<span style=\"background: yellow;\">");
                  html.Append (orgHtml.Substring (start, text.Length));
                  html.Append ("</span>");
                  break;
               }
               if (orgHtml[a] == '<')
               {
                  html.Append (orgHtml.Substring (lastFind, start - lastFind));
                  html.Append (orgHtml.Substring (start, text.Length));
                  break;
               }
            }
            start += text.Length;
            lastFind = start;
         }

         html.Append (orgHtml.Substring (lastFind, orgHtml.Length - lastFind));
         return html.ToString ();
      }

      /// <summary>
      /// Gets a StringFormat Object for the Given ContentAlignment Object.
      /// </summary>
      /// <param name="textalign">Current ContentAlignment.</param>
      /// <returns>StringFormat that Matches the ContentAlignment.</returns>
      public static StringFormat StringFormatAlignment (ContentAlignment textalign)
      {
         StringFormat sf = new StringFormat ();
         switch (textalign)
         {
            case ContentAlignment.TopLeft:
            case ContentAlignment.TopCenter:
            case ContentAlignment.TopRight:
               sf.LineAlignment = StringAlignment.Near;
               break;
            case ContentAlignment.MiddleLeft:
            case ContentAlignment.MiddleCenter:
            case ContentAlignment.MiddleRight:
               sf.LineAlignment = StringAlignment.Center;
               break;
            case ContentAlignment.BottomLeft:
            case ContentAlignment.BottomCenter:
            case ContentAlignment.BottomRight:
               sf.LineAlignment = StringAlignment.Far;
               break;
         }
         switch (textalign)
         {
            case ContentAlignment.TopLeft:
            case ContentAlignment.MiddleLeft:
            case ContentAlignment.BottomLeft:
               sf.Alignment = StringAlignment.Near;
               break;
            case ContentAlignment.TopCenter:
            case ContentAlignment.MiddleCenter:
            case ContentAlignment.BottomCenter:
               sf.Alignment = StringAlignment.Center;
               break;
            case ContentAlignment.TopRight:
            case ContentAlignment.MiddleRight:
            case ContentAlignment.BottomRight:
               sf.Alignment = StringAlignment.Far;
               break;
         }
         return sf;
      }

      /// <summary>
      /// Gets the TD element that was clicked int the given webber.
      /// </summary>
      /// <param name="web">Webber to get TD Element for.</param>
      /// <returns>The needed TD Element.</returns>
      public static HtmlElement GetTdElement (Webber web)
      {
         // Get Cell (TD)...
         HtmlElement elTd = web.GetParentElement (web.ActiveElement, "TD");
         if (elTd == null)
         {
            elTd = web.GetParentElement (web.MouseClickElement, "TD");
            if (elTd == null)
               return null;
         }

         return elTd;
      }

      /// <summary>
      /// Gets the TD element that was clicked int the given webber.
      /// </summary>
      /// <param name="web">Webber to get TD Element for.</param>
      /// <returns>The needed TD Element.</returns>
      public static HtmlElement GetTrElement (Webber web)
      {
         HtmlElement trEl = GetTdElement (web);
         if (trEl != null)
            trEl = web.GetParentElement (trEl, "TR");
         return trEl;
      }
   }
}
